package com.azier.kapacitor;

import com.azier.kapacitor.exception.KapacitorException;
import com.azier.kapacitor.model.*;
import com.azier.kapacitor.util.*;
import com.fasterxml.jackson.core.type.TypeReference;
import org.json.JSONObject;

import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 1 * @Author: luoj
 * 2 * @Date: 2019/8/23 11:29
 * 3
 */
public class Kapacitor {

    private String hostName;

    private int port;

    private String basePath;

    /**
     * 任务相关的基路径
     * 如：定义任务，查询任务等
     */
    public static final String TASK = "tasks";

    /**
     * 模板相关的基路径
     * 如：定义任务，查询任务等
     */
    public static final String TEMPLATE = "templates";

    public Kapacitor(String hostName, int port, String basePath) {
        this.hostName = hostName;
        this.port = port;
        this.basePath = basePath;
    }

    public void setHostName(String hostName) {
        this.hostName = hostName;
    }

    public void setPort(int port) {
        this.port = port;
    }

    public void setBasePath(String basePath) {
        this.basePath = basePath;
    }

    public String getPath() {
        return hostName + ":" + port + basePath;
    }

    /**
     * 任務返回值中存在的特殊字符转换
     *
     * @param result
     * @return
     */
    public static String spiltResult(String result) {
        if (StringUtil.isNotBlank(result)) {
            return result.replaceAll("last-enabled", "lastEnabled").replaceAll("0001-01-01T00:00:00Z","");
        }
        return result;
    }

    /**
     * 将一个对象转换为http参数
     *
     * @param o
     * @return
     * @throws IllegalAccessException
     */
    private Map<String, Object> getParams(Object o) throws IllegalAccessException {
        Class cls = o.getClass();
        Field[] fields = cls.getDeclaredFields();
        Map<String, Object> params = new HashMap<String, Object>();
        for (Field field : fields) {
            field.setAccessible(true);
            //过滤空值
            Class s = field.getType();
            //判断类型为java.Util.Date,则转换为固定格式

            if (field.get(o) != null) {
                if (s == Date.class) {
                    Date date = (Date) field.get(o);
                    params.put(field.getName(), DateUtil.format(date, DateUtil.DATETIME_PATTERN));
                } else {
                    params.put(field.getName(), JsonUtil.toJson(field.get(o)));
                }
            }

        }
        return params;
    }

    @Deprecated
    public String format4Fields2(Map<String, Object> params) {
        String param = null;
        if (params.containsKey("fields")) {
            if (params.get("fields") != null) {
                List<String> fieldList = (List<String>) params.get("fields");
                if (!fieldList.isEmpty()) {
                    StringBuffer stringBuffer = new StringBuffer();
                    for (int i = 0; i < fieldList.size(); i++) {
                        if (i == 0) {
                            stringBuffer.append("fields").append("=").append(fieldList.get(i));
                        } else {
                            stringBuffer.append("&").append("fields").append("=").append(fieldList.get(i));
                        }
                    }
                    param = stringBuffer.toString();
                }
            }
        }
        return param;
    }

    @Deprecated
    public void format4Fields(Map<String, Object> params) {

        if (params.containsKey("fields")) {
            List<String> fieldsList = (List<String>) params.get("fields");
            params.remove("fields");
            if (fieldsList != null && !fieldsList.isEmpty()) {
                StringBuffer stringBuffer = new StringBuffer();
                for (int i = 0; i < fieldsList.size(); i++) {
                    if (i == 0) {
                        stringBuffer.append(fieldsList.get(i));
                    } else {
                        stringBuffer.append("&").append("fields").append("=").append(fieldsList.get(i));
                    }
                }
                params.put("fields", stringBuffer.toString());
            }
        }
    }

    /**
     * 创建任务
     *
     * @param task
     * @return
     * @throws Exception
     */
    public Task createTask(Task task) throws KapacitorException, IOException {
        String url = getPath() + TASK;
        JSONObject jsonObject = new JSONObject();
        if (StringUtil.isBlank(task.getId())) {
            throw new KapacitorException("任务ID不能为空");
        }
        if (task.getType() == null) {
            throw new KapacitorException("任务类型不能为空");
        }
        if (CollectionUtil.isNotEmpty(task.getDbrps())) {
            for (TaskDbrps dbrps : task.getDbrps()) {
                if (StringUtil.isBlank(dbrps.getDb())) {
                    throw new KapacitorException("数据库定义不能为空");
                }
                if (StringUtil.isBlank(dbrps.getRp())) {
                    throw new KapacitorException("保存策略定义不能为空");
                }
            }
        } else {
            throw new KapacitorException("数据库和保存策略定义不能为空");
        }
        if (StringUtil.isBlank(task.getScript())) {
            throw new KapacitorException("脚本内容不能为空");
        }
        jsonObject.put("id", task.getId());
        jsonObject.put("type", task.getType().getName());
        jsonObject.put("dbrps", task.getDbrps());
        jsonObject.put("script", task.getScript());
        if (CollectionUtil.isNotEmpty(task.getVars())) {
            jsonObject.put("vars", task.getVars());
        }

        if (task.getStatus() != null) {
            jsonObject.put("status", task.getStatus().getName());
        }
        String requestJson = HttpUtil.postJson(url, jsonObject.toString());
        requestJson = spiltResult(requestJson);
        checkException(requestJson);
        Task resultTask = JsonUtil.fromJson(requestJson, Task.class);
        return resultTask;
    }

    private void checkException(String requestJson) throws KapacitorException {
        if (StringUtil.indexOfIgnoreCase(requestJson, "error") != -1 && StringUtil.indexOfIgnoreCase(requestJson, "id") == -1) {
            JSONObject errorJson = new JSONObject(requestJson);
            throw new KapacitorException(errorJson.getString("error"));
        }
    }

    /**
     * 创建任务
     *
     * @param jsonObject
     * @return
     * @throws Exception
     */
    public Task createTask(JSONObject jsonObject) throws Exception {
        String url = getPath() + TASK;
        if (!jsonObject.has("id")) {
            throw new KapacitorException("任务ID不能为空");
        }
        if (!jsonObject.has("type")) {
            throw new KapacitorException("任务类型不能为空");
        }
        if (!jsonObject.has("dbrps")) {
            throw new KapacitorException("数据库指定关系不能为空");
        }
        if (!jsonObject.has("script")) {
            throw new KapacitorException("脚本内容不能为空");
        }
        String requestJson = HttpUtil.postJson(url, jsonObject.toString());
        checkException(requestJson);
        requestJson = spiltResult(requestJson);
        Task resultTask = JsonUtil.fromJson(requestJson, Task.class);
        return resultTask;
    }

    /**
     * @param taskId
     * @param type
     * @param dbrps
     * @param script
     * @param vars
     * @param status
     * @return
     * @throws Exception
     */
    public Task createTask(String taskId, Type type, List<TaskDbrps> dbrps, String script, Map<String, Var> vars, Status status) throws Exception {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("id", taskId);
        jsonObject.put("type", type.getName());
        jsonObject.put("dbrps", dbrps);
        jsonObject.put("script", script);
        jsonObject.put("vars", vars);
        if (status != null) {
            jsonObject.put("status", status.getName());
        }
        return createTask(jsonObject);
    }

    /**
     * 修改task 只修改非null属性
     * 注意:1.像修改时间、创建时间等属性不会修改
     * 2.id属性必需存在
     *
     * @param task
     */
    public Task modifyTaskSelective(Task task) throws KapacitorException, IOException {
        //
        String url = getPath() + TASK;
        JSONObject jsonObject = new JSONObject();
        if (StringUtil.isNotBlank(task.getId())) {
            url = url + "/" + task.getId();
        } else {
            throw new KapacitorException("任务ID不能为空");
        }

        if (task.getType() != null) {
            if (StringUtil.isNotBlank(task.getScript())) {
                jsonObject.put("type", task.getType().getName());
            } else {
                throw new KapacitorException("请确保任务脚本和任务类型同时出现");
            }
        }
        if (StringUtil.isNotBlank(task.getScript())) {
            if (task.getType() != null) {
                jsonObject.put("script", task.getScript());
            } else {
                throw new KapacitorException("请确保任务脚本和任务类型同时出现");
            }
        }
        if (CollectionUtil.isNotEmpty(task.getDbrps())) {
            for (TaskDbrps dbrps : task.getDbrps()) {
                if (StringUtil.isBlank(dbrps.getDb())) {
                    throw new KapacitorException("数据库定义不能为空");
                }
                if (StringUtil.isBlank(dbrps.getRp())) {
                    throw new KapacitorException("保存策略定义不能为空");
                }
            }
            jsonObject.put("dbrps", task.getDbrps());
        }
        if (task.getStatus() != null) {
            jsonObject.put("status", task.getStatus().getName());
        }
        if (CollectionUtil.isNotEmpty(task.getVars())) {
            jsonObject.put("vars", task.getVars());
        }
        String requestJson = HttpUtil.patchJson(url, jsonObject.toString());
        checkException(requestJson);
        requestJson = spiltResult(requestJson);
        Task resultTask = JsonUtil.fromJson(requestJson, Task.class);
        return resultTask;
    }

    /**
     * 检索kapacitor中指定ID的任务
     *
     * @param taskId
     * @return
     * @throws Exception
     */
    public Task getTaskByTaskId(String taskId) throws IOException, KapacitorException {
        String url = getPath() + TASK;
        url = url + "/" + taskId;
        String requestJson = HttpUtil.get(url);
        checkException(requestJson);
        requestJson = spiltResult(requestJson);
        Task task = JsonUtil.fromJson(requestJson, Task.class);
        return task;
    }

    /**
     * 检索kapacitor中指定ID的任务
     *
     * @param taskId
     * @param params *  params 的可选key-value 为
     *               *      pattern：TASK* 全文检索 正则
     *               *      fields：List<String>对返回的字段进行过滤 --可以有多个此键值对 ---此项不可用
     *               *      dot-view： 不明
     * @return
     * @throws Exception
     */
    public Task getTaskByTaskId(String taskId, Map<String, Object> params) throws IOException, KapacitorException {
        String url = getPath() + TASK;
        url = url + "/" + taskId;
        String requestJson = HttpUtil.get(url, params);
        checkException(requestJson);
        requestJson = spiltResult(requestJson);
        Task task = JsonUtil.fromJson(requestJson, Task.class);
        return task;
    }
    /**
     * 检索kapacitor中所有符合要求的任务列表
     * @return
     * @throws Exception
     */
    public List<Task> getAllTasks() throws IOException, KapacitorException {
        return  getAllTasks(null);
    }
    /**
     * 检索kapacitor中所有符合要求的任务列表
     *
     * @param params params 的可选key-value 为
     *               pattern：TASK* 全文检索 正则
     *               fields：List<String>对返回的字段进行过滤 --可以有多个此键值对 ---此项不可用
     *               dot-view： 不明
     *               offset ：偏移
     *               limit ：最大返回数
     * @return
     * @throws Exception
     */
    public List<Task> getAllTasks(Map<String, Object> params) throws IOException, KapacitorException {
        String url = getPath() + TASK;
        String requestJson = HttpUtil.get(url, params);
        checkException(requestJson);
        requestJson = spiltResult(requestJson);

        TaskList tasks = JsonUtil.fromJson(requestJson, new TypeReference<TaskList>() {
        });
        return tasks.getTasks();
    }

    /**
     * 检索kapacitor中所有符合要求的任务列表
     *
     * @param params params 的可选key-value 为
     *               pattern：TASK* 全文检索 正则
     *               fields：对返回的字段进行过滤 --可以有多个此键值对
     *               dot-view：
     * @return
     * @throws Exception
     */
    public List<Task> getAllTasksByPage(Map<String, Object> params, int pageSize, int pageNum) throws KapacitorException, IOException {
        if (pageSize <= 0 || pageNum <= 0) {
            throw new KapacitorException("分页数和分页数量必须大于0");
        }
        String url = getPath() + TASK;
        if (params == null || params.isEmpty()) {
            params = new HashMap<>();
        }
        params.put("offset", (pageNum - 1) * pageSize);
        params.put("limit", pageSize);
        return getAllTasks(params);
    }

    /**
     * 分页查询全部任务
     *
     * @param pageSize
     * @param pageNum  从1开始
     * @return
     * @throws Exception
     */
    public List<Task> getAllTasksByPage(int pageSize, int pageNum) throws KapacitorException, IOException {
        if (pageSize <= 0 || pageNum <= 0) {
            throw new KapacitorException("分页数和分页数量必须大于0");
        }
        Map params = new HashMap<>();
        params.put("offset", (pageNum - 1) * pageSize);
        params.put("limit", pageSize);
        return getAllTasks(params);
    }

    public void deleteTask(String taskId) throws KapacitorException, IOException {
        if(StringUtil.isBlank(taskId)){
            throw new KapacitorException("任务ID不能为空");
        }
        String url = getPath() + TASK + "/" +taskId;
        HttpUtil.delete(url);
    }

    /**
     * 获取最近的缓存数据，只对含有HTTPOut节点的脚本有效
     * @param taskId
     * @return
     * @throws KapacitorException
     * @throws IOException
     */
    public String getCache4HTTPOut(String taskId) throws KapacitorException, IOException {
        if(StringUtil.isBlank(taskId)){
            throw new KapacitorException("任务ID不能为空");
        }
        String url = getPath() + TASK + "/" +taskId + "/mycustom_endpoint";
        String requestJson = HttpUtil.get(url);
        checkException(requestJson);
        return requestJson;
    }

    public String createTemplate(String templateId, Type type, String script) throws KapacitorException, IOException {
        String url = getPath() + TEMPLATE;
        if(StringUtil.isBlank(templateId)){
            throw new KapacitorException("模板ID不能为空");
        }
        if(StringUtil.isBlank(script)){
            throw new KapacitorException("模板脚本不能为空");
        }
        if(type!=null){
            throw new KapacitorException("模板类型不能为空");
        }
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("id", templateId);
        jsonObject.put("type",type.getName());
        jsonObject.put("script",script);
        String result = HttpUtil.postJson(url,jsonObject);
        return result;
    }
}
